package com.oscar.practice.shiro.biz.shiro;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import com.oscar.practice.shiro.util.web.ActionUtil;

/**
 * 全局异常处理
 *
 * @author tongyufu
 *
 */
@Component
public class AuthExceptionHandler implements HandlerExceptionResolver {

    Logger log = LogManager.getLogger();

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
                                         Object handler, Exception ex) {
        boolean isAjax = this.isAjax(request, handler);
        Map<String, Object> model = new HashMap<String, Object>();
        //权限验证失败异常
        if (ex instanceof UnauthorizedException) {
            if (isAjax) {
                response.setHeader("sessionstatus", "authorizationFailure");
                return null;
            }
            model.put("error", "没有操作权限");
            return new ModelAndView("unauthorized.jsp", model);
        }
        if (ex instanceof RuntimeException) {
            //注意：只在开发时打印异常堆栈信息
            log.error(getErrorMessage(new RuntimeException(ex), request), ex);
        } else {
            log.error("", ex);
        }
        model.put("ex", ex);
        return new ModelAndView("common/500.jsp", model);
    }

    private boolean isAjax(HttpServletRequest request, Object handler) {
        boolean isAjax = false;
        String xrequest = request.getHeader("x-requested-with");
        if ("XMLHttpRequest".equalsIgnoreCase(xrequest)) {
            return true;
        }
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            if (handlerMethod.getMethodAnnotation(ResponseBody.class) == null) {
                Class<?> clz = handlerMethod.getMethod().getDeclaringClass();
                if (AnnotationUtils.findAnnotation(clz, RestController.class) != null) {
                    isAjax = true;
                }
            } else {
                isAjax = true;
            }
        }
        return isAjax;
    }

    /**获取发生错误时的请求信息*/
    @SuppressWarnings("unchecked")
    private String getErrorMessage(RuntimeException ex, HttpServletRequest request) {
        StringBuilder sb = new StringBuilder("\n请求参数：{");
        Map<String, String[]> params = request.getParameterMap();
        HttpServletRequest httpServletRequest = ActionUtil.getRequest();

        for (String param : params.keySet()) {
            sb.append("\n\t").append(param).append(":").append(request.getParameter(param));
        }
        sb.append("\n}");
        sb.append("\nIP:" + ActionUtil.getIP());
        sb.append("\nURL：");
        if (httpServletRequest != null) {
            sb.append(httpServletRequest.getMethod() + " ");
        }
        sb.append("\n头信息：{");
        for (Enumeration<String> e = request.getHeaderNames(); e.hasMoreElements();) {
            String header = e.nextElement();
            sb.append("\n\t").append(header).append(":").append(request.getHeader(header));
        }
        sb.append("\n}");
        return sb.toString();
    }

}
